#!/usr/bin/python

import os
import sys
import errno
import glob
import shutil
import logging
import shlex
import subprocess
import commands
import pdb
from optparse import OptionParser

ROUND = 0

MDS_PORT = None
MDS_ENV = None
SPLIT_DIR = '%s.split'
RESTORE_DIR = '%s.restore'
SPLIT_MD5 = '%s.split.%s.%s.md5'
RESTORE_MD5 = '%s.restore.%s.%s.md5'
MD5_DIFF = '%s.md5.%s.%s.diff'


def with_log(log_message=None):
    """
    add log message before and after each function for lazy people
    """
    def with_log_decorator(func):
        """
        the actual decorator
        """
        def with_log_wrapper(*args, **kwargs):
            """
            the wrapper
            """
            _log_message = log_message or 'Call %s' % func.__name__
            logging.info('[Round %s] %s ...', ROUND, _log_message)
            result = func(*args, **kwargs)
            logging.info('[Round %s] %s ... Done', ROUND, _log_message)
            return result

        return with_log_wrapper

    return with_log_decorator


def parse_command_line():
    """
    parse command line options
    """
    usage = """
    Script to automate mdssync db file restore testing
    """
    parser = OptionParser(usage=usage)
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="more log message")
    parser.add_option("-p", "--port", dest="port", help="MDS port")
    parser.add_option("-s", "--start-round", dest="start_round", type='int', help="start round number", default=0)
    parser.add_option("-d", "--debug", dest="debug", action="store_true", help="enable debug mode")

    (options, args) = parser.parse_args()

    if options.verbose:
        logging.basicConfig(level=logging.DEBUG)

    if options.debug:
        pdb.set_trace()

    if not (options.port):
        parser.print_help()
        sys.exit(errno.EINVAL)


    global MDS_PORT
    global ROUND
    global MDS_ENV

    MDS_PORT = options.port
    ROUND = options.start_round
    MDS_ENV = commands.getoutput('mdsdir %s' % options.port)

    return options, args

@with_log('Move MDS env')
def _round_move_mds_env():
    if os.path.isdir(MDS_ENV):
        shutil.rmtree(MDS_ENV)

def _stop_mds():
    global MDS_PORT
    if MDS_PORT.startswith('104'):
        cmd = "service mauimds stop %s"% MDS_PORT
    elif MDS_PORT.startswith('106'):
        cmd = "service mauiremoterep stop %s"% MDS_PORT
    else:
        logging.info("Invalid Port %s", MDS_PORT)
        
    status, output = commands.getstatusoutput(cmd)
    return status

@with_log('Run MDSSync')
def _round_run_mdssync():
    # use -s option to not start mds after mdssync
    # use -R option to reuse src side tmp env so that we donot have to clean up src side tmp env
    # use -k option to keep target side tmp env for 
    cmd = 'python %s -p %s  --force > /dev/null' % ("mdssync.py", MDS_PORT)
    print cmd
    status, output = commands.getstatusoutput(cmd)
    return (status, output)

def _db_verify():
    result = 0
    for file in MDS_ENV:
        if file.endswith('bdbdb'):
            cmd = "db_verify -h %s %s"% (MDS_ENV, file)
            logging.info("db_verify %s SUCCESS", file)
            (status, output) = commands.getstatusoutput(cmd)
            if status != 0:
                logging.error("db_verify error %s", file)
                result = 1
    return result

@with_log('')
def test_round():
    _stop_mds()
    _round_move_mds_env()
    (status,output) = _round_run_mdssync()
    _stop_mds()

    if status == 0:
        logging.info('[Round %s] SUCCESS', ROUND)
    else:
        output = ('\n').join( output.split('\n')[-6 : -1])
        logging.error('[Round %s] FAILED: %s', ROUND, output)
        sys.exit(1)
    logging.info('[Round %s] Check', ROUND)
    result = _db_verify()
    if status == 0:
        logging.info('[Round %s] Check SUCCESS', ROUND)
    else:
        
        logging.error('[Round %s] Check FAILED: %s', ROUND)
        sys.exit(1)

def main():
    options, _ = parse_command_line()

    global ROUND
    
    while ROUND:
        ROUND -= 1
        test_round()

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    main()
